package erfgame.core.world.terrain;

import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;


import erfgame.core.Pair;
import erfgame.core.util.ColorUtils;
import erfgame.core.world.World;
import erfgame.core.world.terrain.color.GridTerrainColorSourceProxy;
import erfgame.core.world.terrain.color.MappedTerrainColorSource;
import erfgame.core.world.terrain.color.QuickMappedTerrainColorSource;
import erfgame.core.world.terrain.color.SimpleTerrainColorSource;

public final class TerrainColorSourceIndex {
	
	
//	private static final int COLOR_GRASS_RYE_MAX_LT = 0x72A926;
//	private static final int COLOR_GRASS_RYE_MIN_LT = 0x042004;
//	private static final int COLOR_GRASS_RYE_MAX_LT = 0x708010;
//	private static final int COLOR_GRASS_RYE_MIN_LT = 0x043004;
	private static final int COLOR_GRASS_RYE_MAX_LT = 0x707610;
	private static final int COLOR_GRASS_RYE_MIN_LT = 0x042804;
//	private static final int COLOR_GRASS_RYE_MAX_LT = 0x0000FF;
//	private static final int COLOR_GRASS_RYE_MIN_LT = 0xFF0000;
	//private static final int COLOR_GRASS_RYE_MAX = 0x407a11;
	//private static final int COLOR_GRASS_RYE_MIN = 0x1a450f;
	private static final int COLOR_GRASS_RYE_MAX = 0x3c5300;
	private static final int COLOR_GRASS_RYE_MIN = 0x41360d;
//	private static final int COLOR_GRASS_RYE_MAX = 0x3c5b00;
//	private static final int COLOR_GRASS_RYE_MIN = 0x41360d;
	private static final int COLOR_GRASS_RYE_DIMENSIONS = 1 << 6;
	private static final int COLOR_GRASS_RYE_DIMENSIONS_MASK = COLOR_GRASS_RYE_DIMENSIONS - 1;
	
	private static final int COLOR_SOIL_MIN = 0x39271b;
	private static final int COLOR_SOIL_MAX = 0x664f3f;
	private static final int COLOR_SOIL_MAX_LT = 0x876f4a;
	private static final int COLOR_SOIL_MIN_LT = 0x190704;
	private static final int COLOR_SOIL_DIMENSIONS = 1 << 5;
	private static final int COLOR_SOIL_DIMENSIONS_MASK = COLOR_SOIL_DIMENSIONS - 1;
	
	
	private static final int COLOR_OBSIDIAN_MAX_LT=0x505050;
	private static final int COLOR_OBSIDIAN_MIN_LT=0x202020;
	private static final int COLOR_OBSIDIAN=0x333333;

	private static final int COLOR_BLACK_GRID_MIN_LT = 0xFF000000;
	private static final int COLOR_BLACK_GRID_MAX_LT = 0xFF444444;
	private static final int COLOR_BLACK_GRID = 0xFF222222;

	private static final int COLOR_WHITE_GRID_MIN_LT = 0xCCCCCC;
	private static final int COLOR_WHITE_GRID_MAX_LT = 0x999999;
	private static final int COLOR_WHITE_GRID = 0xAAAAAA;
	
	private static final int COLOR_BRICK_MUD_MIN = COLOR_SOIL_MIN;
	private static final int COLOR_BRICK_MUD_MAX = COLOR_SOIL_MAX;
	private static final int COLOR_BRICK_MUD_MAX_LT = COLOR_SOIL_MAX_LT;
	private static final int COLOR_BRICK_MUD_MIN_LT = COLOR_SOIL_MIN_LT;

	private static final int COLOR_BRICK_MUD_X_MULT = 2;
	private static final int COLOR_BRICK_MUD_Y_MULT = 2;
	private static final int COLOR_BRICK_MUD_Z_MULT = 4;
	
	private static final int COLOR_UNDEFINED_MIN_LT = 0x0000FF;
	private static final int COLOR_UNDEFINED_MAX_LT = 0xFF0000;
	private static final int COLOR_UNDEFINED 		= 0x00FF00;
	
	private TerrainColorSource[] colorSources = new TerrainColorSource[256];
	
	public TerrainColorSourceIndex( 
			List<Pair<MaterialType, TerrainColorSource>> terrainColorSources, 
			TerrainColorSource defaultColorSource 
	) {
		for( int i=colorSources.length; i>0; ) {
			i--;
			colorSources[i] = defaultColorSource;
		}
		for( int i=terrainColorSources.size(); i>0; ) {
			i--;
			Pair<MaterialType, TerrainColorSource> pair = terrainColorSources.get( i );
			int id = pair.getFirst().getId();
			TerrainColorSource colorSource = pair.getSecond();
			colorSources[id+128] = colorSource;
		}
	}
	
	public TerrainColorSourceIndex ( World world, GridSettings gridSettings ) {
		Random random = new Random( 97534317 );
		
		TerrainColorSource blackGridColorSource = new SimpleTerrainColorSource( COLOR_BLACK_GRID_MIN_LT, COLOR_BLACK_GRID_MAX_LT, COLOR_BLACK_GRID );
		//TerrainColorSource blackGridColorSource = new SimpleTerrainColorSource( 0xFFFFFF, 0x000000, 0x888888 );
		TerrainColorSource whiteGridColorSource = new SimpleTerrainColorSource( COLOR_WHITE_GRID_MIN_LT, COLOR_WHITE_GRID_MAX_LT, COLOR_WHITE_GRID );
		
		TerrainColorSource grayTerrainColorSource = new GridTerrainColorSourceProxy(
				new SimpleTerrainColorSource( 0x000000, 0xFFFFFF, 0x777777 ), 
				blackGridColorSource, 
				world,
				gridSettings
		);
		
		TerrainColorSource undefinedColorSource = new SimpleTerrainColorSource( COLOR_UNDEFINED_MIN_LT, COLOR_UNDEFINED_MAX_LT, COLOR_UNDEFINED );
		for( int i=0; i<colorSources.length; i++ ) {
			this.colorSources[ i ] = undefinedColorSource;
		}

//		this.colorSources[ TerrainConstants.TERRAIN_TYPE_GRASS_RYE ] = new QuickMappedTerrainColorSource(
//				GridTerrainColorSourceProxy.overlayGrid(
//						MappedTerrainColorSource.getRandomColorMap(
//								COLOR_GRASS_RYE_MIN_LT, 
//								COLOR_GRASS_RYE_MIN, 
//								random, 
//								COLOR_GRASS_RYE_DIMENSIONS, 
//								COLOR_GRASS_RYE_DIMENSIONS, 
//								COLOR_GRASS_RYE_DIMENSIONS
//						),
//						COLOR_GRASS_RYE_DIMENSIONS, 
//						COLOR_GRASS_RYE_DIMENSIONS, 
//						COLOR_GRASS_RYE_DIMENSIONS,
//						COLOR_BLACK_GRID_MIN_LT, 
//						world.getGridDiagonalMask(), 
//						gridSettings
//				),
//				GridTerrainColorSourceProxy.overlayGrid(
//						MappedTerrainColorSource.getRandomColorMap( 
//								COLOR_GRASS_RYE_MAX, 
//								COLOR_GRASS_RYE_MAX_LT, 
//								random, 
//								COLOR_GRASS_RYE_DIMENSIONS, 
//								COLOR_GRASS_RYE_DIMENSIONS, 
//								COLOR_GRASS_RYE_DIMENSIONS
//						), 
//						COLOR_GRASS_RYE_DIMENSIONS, 
//						COLOR_GRASS_RYE_DIMENSIONS, 
//						COLOR_GRASS_RYE_DIMENSIONS,
//						COLOR_BLACK_GRID_MAX_LT, 
//						world.getGridDiagonalMask(), 
//						gridSettings
//				),
//				GridTerrainColorSourceProxy.overlayGrid(
//						MappedTerrainColorSource.getRandomColorMap( 
//								COLOR_GRASS_RYE_MIN, 
//								COLOR_GRASS_RYE_MAX, 
//								random, 
//								COLOR_GRASS_RYE_DIMENSIONS, 
//								COLOR_GRASS_RYE_DIMENSIONS, 
//								COLOR_GRASS_RYE_DIMENSIONS
//						), 
//						COLOR_GRASS_RYE_DIMENSIONS, 
//						COLOR_GRASS_RYE_DIMENSIONS, 
//						COLOR_GRASS_RYE_DIMENSIONS,
//						COLOR_BLACK_GRID, 
//						world.getGridDiagonalMask(), 
//						gridSettings
//				),
//				COLOR_GRASS_RYE_DIMENSIONS_MASK, COLOR_GRASS_RYE_DIMENSIONS_MASK, COLOR_GRASS_RYE_DIMENSIONS_MASK
//		);

//		this.colorSources[ TerrainConstants.TERRAIN_TYPE_GRASS_RYE ] = new GridTerrainColorSourceProxy( 
//				new QuickSampledTerrainColorSource(
//					SampledTerrainColorSource.getRandomColors(
//							COLOR_GRASS_RYE_MIN, 
//							COLOR_GRASS_RYE_MIN_LT, 
//							random, 
//							new int[COLOR_GRASS_RYE_DIMENSIONS] 
//					),
//					SampledTerrainColorSource.getRandomColors(
//							COLOR_GRASS_RYE_MAX, 
//							COLOR_GRASS_RYE_MAX_LT,
//							random, 
//							new int[COLOR_GRASS_RYE_DIMENSIONS] 
//					),
//					SampledTerrainColorSource.getRandomColors(
//							COLOR_GRASS_RYE_MIN, 
//							COLOR_GRASS_RYE_MAX, 
//							random, 
//							new int[COLOR_GRASS_RYE_DIMENSIONS] 
//					), 
//					COLOR_GRASS_RYE_DIMENSIONS_MASK
//				), 
//				blackGridColorSource,
//				world,
//				gridSettings
//		);
		
//		this.colorSources[ TerrainConstants.TERRAIN_TYPE_GRASS_RYE ] = new GridTerrainColorSourceProxy( 
//				new MappedTerrainColorSource(
//					MappedTerrainColorSource.getRandomColorMap( COLOR_GRASS_RYE_MIN_LT, COLOR_GRASS_RYE_MIN, random, COLOR_GRASS_RYE_DIMENSIONS, COLOR_GRASS_RYE_DIMENSIONS, 1), 
//					MappedTerrainColorSource.getRandomColorMap( COLOR_GRASS_RYE_MAX, COLOR_GRASS_RYE_MAX_LT, random, COLOR_GRASS_RYE_DIMENSIONS, COLOR_GRASS_RYE_DIMENSIONS, 1), 
//					MappedTerrainColorSource.getRandomColorMap( COLOR_GRASS_RYE_MIN, COLOR_GRASS_RYE_MAX, random, COLOR_GRASS_RYE_DIMENSIONS, COLOR_GRASS_RYE_DIMENSIONS, 1), 
//					COLOR_GRASS_RYE_DIMENSIONS, COLOR_GRASS_RYE_DIMENSIONS, 1
//				), 
//				blackGridColorSource, 
//				gridSettings
//		);
//		this.colorSources[ TerrainConstants.TERRAIN_TYPE_SOIL ] = new QuickMappedTerrainColorSource(
//				GridTerrainColorSourceProxy.overlayGrid(
//						MappedTerrainColorSource.getRandomColorMap(
//								COLOR_SOIL_MIN_LT, COLOR_SOIL_MIN, random, COLOR_SOIL_DIMENSIONS, COLOR_SOIL_DIMENSIONS, COLOR_SOIL_DIMENSIONS
//						),
//						COLOR_SOIL_DIMENSIONS, 
//						COLOR_SOIL_DIMENSIONS, 
//						COLOR_SOIL_DIMENSIONS,
//						COLOR_BLACK_GRID_MIN_LT, 
//						world.getGridDiagonalMask(), 
//						gridSettings
//				),
//				GridTerrainColorSourceProxy.overlayGrid(
//						MappedTerrainColorSource.getRandomColorMap( 
//								COLOR_SOIL_MAX, COLOR_SOIL_MAX_LT, random, COLOR_SOIL_DIMENSIONS, COLOR_SOIL_DIMENSIONS, COLOR_SOIL_DIMENSIONS
//						), 
//						COLOR_SOIL_DIMENSIONS, 
//						COLOR_SOIL_DIMENSIONS, 
//						COLOR_SOIL_DIMENSIONS,
//						COLOR_BLACK_GRID_MAX_LT, 
//						world.getGridDiagonalMask(), 
//						gridSettings
//				),
//				GridTerrainColorSourceProxy.overlayGrid(
//						MappedTerrainColorSource.getRandomColorMap( 
//								COLOR_SOIL_MIN, COLOR_SOIL_MAX, random, COLOR_SOIL_DIMENSIONS, COLOR_SOIL_DIMENSIONS, COLOR_SOIL_DIMENSIONS
//						), 
//						COLOR_SOIL_DIMENSIONS, 
//						COLOR_SOIL_DIMENSIONS, 
//						COLOR_SOIL_DIMENSIONS,
//						COLOR_BLACK_GRID, 
//						world.getGridDiagonalMask(), 
//						gridSettings
//				),
//				COLOR_SOIL_DIMENSIONS_MASK, COLOR_SOIL_DIMENSIONS_MASK, COLOR_SOIL_DIMENSIONS_MASK
//		);

		this.colorSources[ TerrainConstants.TERRAIN_TYPE_OBSIDIAN ] = new GridTerrainColorSourceProxy( 
				new SimpleTerrainColorSource(
					COLOR_OBSIDIAN_MIN_LT, COLOR_OBSIDIAN_MAX_LT, COLOR_OBSIDIAN
				), 
				blackGridColorSource,
				world,
				gridSettings
		);
		
//		this.colorSources[ TerrainConstants.TERRAIN_TYPE_BRICKS_MUD ] = new GridTerrainColorSourceProxy( 
//				new MappedTerrainColorSource(
//						COLOR_BRICK_MUD_MIN_LT, 
//						COLOR_BRICK_MUD_MAX_LT, 
//						MappedTerrainColorSource.carveBricks( 
//								COLOR_BRICK_MUD_GAP, 
//								COLOR_BRICK_MUD_WIDTH, 
//								COLOR_BRICK_MUD_HEIGHT, 
//								COLOR_BRICK_MUD_DEPTH, 
//								MappedTerrainColorSource.getRandomColorMap(
//										COLOR_BRICK_MUD_MIN, 
//										COLOR_BRICK_MUD_MAX, 
//										random, 
//										COLOR_BRICK_MUD_WIDTH, 
//										COLOR_BRICK_MUD_HEIGHT, 
//										COLOR_BRICK_MUD_DEPTH
//								)
//						), 
//						COLOR_BRICK_MUD_WIDTH, 
//						COLOR_BRICK_MUD_HEIGHT, 
//						COLOR_BRICK_MUD_DEPTH						
//				),
//				blackGridColorSource, 
//				gridSettings
//		);

		try {
			BufferedImage basketWeaveTile = ImageIO.read(  
					TerrainColorSourceIndex.class.getResource( "/img/tiles/basket-weave.png" ) 
			);
			BufferedImage herringBoneTile = ImageIO.read( 
					TerrainColorSourceIndex.class.getResource( "/img/tiles/herringbone.png" ) 
			);
			BufferedImage gapTile = ImageIO.read( 
					TerrainColorSourceIndex.class.getResource( "/img/tiles/break_1x4.png" ) 
			);
			int mapWidth = COLOR_BRICK_MUD_X_MULT * basketWeaveTile.getWidth();
			int mapHeight = COLOR_BRICK_MUD_Y_MULT * basketWeaveTile.getHeight();
			int mapDepth = COLOR_BRICK_MUD_Z_MULT * gapTile.getHeight();

			this.colorSources[ TerrainConstants.TERRAIN_TYPE_BRICKS_MUD ] = 
				new MappedTerrainColorSource(
						makeBricks( 
								basketWeaveTile, 
								gapTile, 
								mapWidth, 
								mapHeight, 
								mapDepth, 
								MappedTerrainColorSource.getRandomColorMap(
										COLOR_BRICK_MUD_MIN, 
										COLOR_BRICK_MUD_MIN_LT, 
										random, 
										mapWidth, 
										mapHeight, 
										mapDepth
								)
						),
						makeBricks( 
								basketWeaveTile, 
								gapTile, 
								mapWidth, 
								mapHeight, 
								mapDepth, 
								MappedTerrainColorSource.getRandomColorMap(
										COLOR_BRICK_MUD_MAX_LT, 
										COLOR_BRICK_MUD_MAX, 
										random, 
										mapWidth, 
										mapHeight, 
										mapDepth
								)
						),
						makeBricks( 
								basketWeaveTile, 
								gapTile, 
								mapWidth, 
								mapHeight, 
								mapDepth, 
								MappedTerrainColorSource.getRandomColorMap(
										COLOR_BRICK_MUD_MIN, 
										COLOR_BRICK_MUD_MAX, 
										random, 
										mapWidth, 
										mapHeight, 
										mapDepth
								)
						),
						mapWidth, 
						mapHeight, 
						mapDepth 
				);

			this.colorSources[ TerrainConstants.TERRAIN_TYPE_BRICKS_OBSIDIAN ] = 
				new MappedTerrainColorSource(
						makeBricks( 
								herringBoneTile, 
								gapTile, 
								mapWidth, 
								mapHeight, 
								mapDepth, 
								MappedTerrainColorSource.getStaticColorMap(
										COLOR_OBSIDIAN_MIN_LT, 
										mapWidth, 
										mapHeight, 
										mapDepth
								)
						),
						makeBricks( 
								herringBoneTile, 
								gapTile, 
								mapWidth, 
								mapHeight, 
								mapDepth, 
								MappedTerrainColorSource.getStaticColorMap(
										COLOR_OBSIDIAN_MAX_LT, 
										mapWidth, 
										mapHeight, 
										mapDepth
								)
						),
						makeBricks( 
								herringBoneTile, 
								gapTile, 
								mapWidth, 
								mapHeight, 
								mapDepth, 
								MappedTerrainColorSource.getStaticColorMap(
										COLOR_OBSIDIAN,
										mapWidth, 
										mapHeight, 
										mapDepth
								)
						),
						mapWidth, 
						mapHeight, 
						mapDepth 
				);

		} catch( Exception ex ) {
			ex.printStackTrace();
		}
		//this.colorSources[ TerrainConstants.TERRAIN_TYPE_GRASS_RYE ] = new SimpleTerrainColorSource( 0x000000, 0xFFFFFF, 0x777777 );
		int mapWidth = 64;
		int mapHeight = 64;
		int mapDepth = 64;
//		this.colorSources[ TerrainConstants.TERRAIN_TYPE_BRICKS_OBSIDIAN ] = 
//			new MappedTerrainColorSource(
//					carveBlocks( 
//							MappedTerrainColorSource.getStaticColorMap(
//									COLOR_OBSIDIAN,
//									mapWidth, 
//									mapHeight, 
//									mapDepth
//							), 
//							MappedTerrainColorSource.getStaticColorMap(
//									COLOR_OBSIDIAN_MIN_LT,
//									mapWidth, 
//									mapHeight, 
//									mapDepth
//							), 
//							mapWidth, 
//							mapHeight, 
//							mapDepth, 
//							new SphereMaskFactory( 5 ), 
//							600, 
//							random
//					),
//					carveBlocks( 
//							MappedTerrainColorSource.getStaticColorMap(
//									COLOR_OBSIDIAN,
//									mapWidth, 
//									mapHeight, 
//									mapDepth
//							), 
//							MappedTerrainColorSource.getStaticColorMap(
//									COLOR_OBSIDIAN_MAX_LT,
//									mapWidth, 
//									mapHeight, 
//									mapDepth
//							), 
//							mapWidth, 
//							mapHeight, 
//							mapDepth, 
//							new SphereMaskFactory( 5 ), 
//							600, 
//							random
//					),
//					carveBlocks( 
//							MappedTerrainColorSource.getStaticColorMap(
//									COLOR_OBSIDIAN_MIN_LT,
//									mapWidth, 
//									mapHeight, 
//									mapDepth
//							), 
//							MappedTerrainColorSource.getStaticColorMap(
//									COLOR_OBSIDIAN,
//									mapWidth, 
//									mapHeight, 
//									mapDepth
//							), 
//							mapWidth, 
//							mapHeight, 
//							mapDepth, 
//							new SphereMaskFactory( 5 ), 
//							600, 
//							random
//					),
//					mapWidth, 
//					mapHeight, 
//					mapDepth 
//			);
	}
	
	public TerrainColorSource getTerrainColorSource( byte terrainType ) {
		// TODO : negative terrain types?!
		return this.colorSources[ ((int)terrainType) + 128 ];
	}
	
	public static final BufferedImage rotate90( BufferedImage source ) {
		BufferedImage result = new BufferedImage( source.getHeight(), source.getWidth(), BufferedImage.TYPE_INT_ARGB );
		for( int x=0; x<source.getWidth(); x++ ) {
			for( int y=0; y<source.getHeight(); y++ ) {
				result.setRGB( y, x, source.getRGB( x, y ) );
			}
		}
		return result;
	}
	
	public static final BufferedImage shift( BufferedImage source, int dx, int dy ) {
		BufferedImage result = new BufferedImage( source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_ARGB );
		for( int x=0; x<source.getWidth(); x++ ) {
			for( int y=0; y<source.getHeight(); y++ ) {
				int px = ( x + dx )%source.getWidth();
				int py = ( y + dy )%source.getHeight();
				result.setRGB( px, py, source.getRGB( x, y ) );
			}
		}
		return result;		
	}
	
	public static final int[][][] carveBlocks( int[][][] blockSource, int[][][] into, int mapWidth, int mapHeight, int mapDepth, MaskFactory maskFactory, int attempts, Random random ) {
		// TODO : make diagonal area only
		int fillWidth = mapWidth;
		int fillHeight = mapHeight;
		int fillDepth = mapDepth;
		byte[][][] mask = new byte[ fillWidth ][ fillHeight ][ fillDepth ];
		for( int i=0; i<attempts; i++ ) {
			int x = Math.abs( random.nextInt() ) % fillWidth;
			int y = Math.abs( random.nextInt() ) % fillHeight;
			int z = Math.abs( random.nextInt() ) % fillDepth;
			 
//  			byte[][][] fitInMask = maskFactory.getMask( 
//  					Math.abs( random.nextInt() ) % fillWidth/2 + fillWidth/4, 
//  					Math.abs( random.nextInt() ) % fillHeight/2 + fillHeight/4, 
//  					Math.abs( random.nextInt() ) % fillDepth/2 + fillDepth/4 
//  			);
			int d = Math.abs( random.nextInt() ) % fillWidth/2 + fillWidth/8; 
			byte[][][] fitInMask = maskFactory.getMask( 
					d, d, d 
			);
			boolean fits = true;
			outer: for( int mx=0; mx<fitInMask.length; mx++ ) {
				byte[][] fitInMaskX = fitInMask[mx];
				for( int my=0; my<fitInMaskX.length; my++ ) {
					byte[] fitInMaskXY = fitInMaskX[my];
					for( int mz=0; mz<fitInMaskXY.length; mz++ ) {
						byte fitInMaskXYZ = fitInMaskXY[mz];
						if( fitInMaskXYZ != 0 ) {
							int tx = (x + mx)%fillWidth;
							int ty = (y + my)%fillHeight;
							int tz = (z + mz)%fillDepth;
							byte targetMaskXYZ = mask[tx][ty][tz];
							if( targetMaskXYZ != 0 ) {
								fits = false;
								break outer;
							}
						}
					}
				}
			}
			if( fits ) {
				for( int mx=0; mx<fitInMask.length; mx++ ) {
					byte[][] fitInMaskX = fitInMask[mx];
					for( int my=0; my<fitInMaskX.length; my++ ) {
						byte[] fitInMaskXY = fitInMaskX[my];
						for( int mz=0; mz<fitInMaskXY.length; mz++ ) {
							byte fitInMaskXYZ = fitInMaskXY[mz];
							if( fitInMaskXYZ != 0 ) {
								int tx = (x + mx)%fillWidth;
								int ty = (y + my)%fillHeight;
								int tz = (z + mz)%fillDepth;
								if( (0xFF & fitInMaskXYZ) > (0xFF & mask[tx][ty][tz]) ) {
									mask[tx][ty][tz] = fitInMaskXYZ;
								}
							}
						}
					}				
				}
			}
		}
		int[][][] result = into;
		for( int x = 0; x<mapWidth; x++ ) {
			for( int y = 0; y<mapHeight; y++ ) {
				for( int z = 0; z<mapDepth; z++ ) {
					int existing = result[x][y][z];
					int transparency = 0xFF & mask[x][y][z];
					if( transparency != 0 ) {
						int insert = blockSource[x][y][z];
						int bit = ColorUtils.averageColors( existing, 255 - transparency , insert, transparency );
						result[x][y][z] = bit;
					}
				}
			}
		}
		return result;
	}
	
	public static final int[][][] makeBricks( BufferedImage topTile, BufferedImage gapTile, int mapWidth, int mapHeight, int mapDepth, int[][][] colorMap  ) {
		
		MappedTerrainColorSource.overlayXZ(
				gapTile, 
				mapWidth, 
				0, 
				mapHeight, 
				mapDepth,
				colorMap
		);
		for( int z = 0; z<COLOR_BRICK_MUD_Z_MULT; z++ ) {
			MappedTerrainColorSource.overlayXY(
					topTile,
					mapWidth, 
					mapHeight, 
					z * gapTile.getHeight(),
					(z+1) * gapTile.getHeight(), 
					colorMap
			);
			// rotate the tile
			topTile = rotate90( topTile );
			topTile = shift( 
					topTile, 
					((z+1) * topTile.getWidth())/COLOR_BRICK_MUD_Z_MULT,
					((z+1) * topTile.getHeight())/COLOR_BRICK_MUD_Z_MULT
			);
		}
		return colorMap;
	}
}
